package com.mlethe.library.multi.api;

import android.app.Activity;
import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.text.TextUtils;

import androidx.annotation.NonNull;
import androidx.credentials.ClearCredentialStateRequest;
import androidx.credentials.Credential;
import androidx.credentials.CredentialManager;
import androidx.credentials.CredentialManagerCallback;
import androidx.credentials.CustomCredential;
import androidx.credentials.GetCredentialRequest;
import androidx.credentials.GetCredentialResponse;
import androidx.credentials.exceptions.ClearCredentialException;
import androidx.credentials.exceptions.GetCredentialCancellationException;
import androidx.credentials.exceptions.GetCredentialException;

import com.alipay.sdk.app.AuthTask;
import com.facebook.AccessToken;
import com.facebook.CallbackManager;
import com.facebook.FacebookCallback;
import com.facebook.FacebookException;
import com.facebook.FacebookRequestError;
import com.facebook.GraphRequest;
import com.facebook.login.LoginManager;
import com.facebook.login.LoginResult;
import com.google.android.libraries.identity.googleid.GetGoogleIdOption;
import com.google.android.libraries.identity.googleid.GoogleIdTokenCredential;
import com.mlethe.library.multi.api.entity.AuthResult;
import com.mlethe.library.multi.api.listener.Callback;
import com.mlethe.library.multi.api.listener.OnActionCallback;
import com.mlethe.library.multi.api.listener.OnActionListener;
import com.out.UPAuthStart;
import com.sina.weibo.sdk.auth.Oauth2AccessToken;
import com.sina.weibo.sdk.auth.WbAuthListener;
import com.sina.weibo.sdk.common.UiError;
import com.sina.weibo.sdk.openapi.IWBAPI;
import com.tencent.mm.opensdk.modelmsg.SendAuth;
import com.tencent.mm.opensdk.openapi.IWXAPI;
import com.tencent.tauth.Tencent;

import org.json.JSONObject;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executor;

/**
 * 授权登录
 *
 * @author Mlethe
 * @date 2024/12/12
 */
public final class OauthAction {
    /**
     * 授权方式
     */
    private final MultiMedia mMultiMedia;

    /**
     * 回调监听
     */
    private OnActionListener mListener;

    /**
     * 是否获取用户信息
     */
    private boolean isGetUserInfo = true;

    /**
     * 微信、QQ、云闪付、Facebook的信息授权域
     */
    private String scope;

    /**
     * 支付宝账户授权业务信息
     */
    private String authInfo;

    /**
     * 云闪付用于进行业务流程的 Id
     */
    private String planId;

    public OauthAction(MultiMedia mMultiMedia) {
        this.mMultiMedia = mMultiMedia;
    }

    /**
     * 授权登录回调
     *
     * @param listener
     * @return
     */
    public OauthAction setCallback(OnActionListener listener) {
        this.mListener = listener;
        return this;
    }

    /**
     * 是否获取用户信息
     *
     * @param flag true 是 false 否
     */
    public OauthAction setGetUserInfo(boolean flag) {
        this.isGetUserInfo = flag;
        return this;
    }

    /**
     * 微信、QQ、云闪付、Facebook的信息授权域，用“,”隔开
     *
     * @param scope 微信：使用逗号（,）分隔【用户个人信息 snsapi_userinfo】
     *              QQ：默认 all
     *              云闪付：为空直接返回，可传入多个，用“,”隔开【联登 scope.base；手机号 scope.mobile；实名 scope.auth】
     *              Facebook：默认用户个人信息 public_profile
     */
    public OauthAction setScope(String scope) {
        this.scope = scope;
        return this;
    }

    /**
     * 支付宝账户授权业务信息
     *
     * @param authInfo
     * @return
     */
    public OauthAction setAuthInfo(String authInfo) {
        this.authInfo = authInfo;
        return this;
    }

    /**
     * 云闪付用于进行业务流程的 Id
     *
     * @param planId
     */
    public OauthAction setPlanId(String planId) {
        this.planId = planId;
        return this;
    }

    /**
     * 授权
     *
     * @return true 启动成功，false 启动失败
     */
    public boolean oauth(Activity activity) {
        OnActionListener listener = mListener;
        mListener = null;
        MultiApi instance = MultiApi.getInstance();
        Context context = instance.getContext();
        if (context == null) {
            onFailure(instance, listener, -8000, "MultiApi未初始化");
            return false;
        }
        if (MultiMedia.WECHAT == mMultiMedia) {
            IWXAPI api = instance.getWXApi();
            if (api == null) {
                onFailure(instance, listener, -8005, context.getString(R.string.multi_api_not_initialized_successfully));
                return false;
            }
            if (!instance.isInstalled(mMultiMedia)) {
                // 未安装微信
                onFailure(instance, listener, -8001, context.getString(R.string.multi_api_app_not_installed));
                return false;
            }
            SendAuth.Req authReq = new SendAuth.Req();
            String currScope = scope;
            if (scope == null || scope.isEmpty()) {
                currScope = "snsapi_userinfo";
            }
            authReq.scope = currScope;
            String state = Util.buildState();
            authReq.transaction = state;
            OnActionCallback callback = new OnActionCallback(1, listener);
            callback.state = state;
            callback.isGetUserInfo = isGetUserInfo;
            instance.setMultiMedia(mMultiMedia)
                    .setActionCallback(callback);
            try {
                if (api.sendReq(authReq)) {
                    return true;
                }
                instance.e("WECHAT oauth launch fail.");
                instance.release();
                onFailure(instance, listener, -8004, context.getString(R.string.multi_api_filter_logs_check_reason, "MicroMsg.SDK"));
            } catch (Throwable t) {
                instance.e("WECHAT oauth launch fail.", t);
                instance.release();
                onFailure(instance, listener, -8004, t.getMessage());
            }
            return false;
        } else if (MultiMedia.QQ == mMultiMedia) {
            Tencent tencent = instance.getTencent();
            if (tencent == null) {
                onFailure(instance, listener, -8005, context.getString(R.string.multi_api_not_initialized_successfully));
                return false;
            }
            if (!instance.isInstalled(mMultiMedia)) {
                // 未安装QQ
                onFailure(instance, listener, -8001, context.getString(R.string.multi_api_app_not_installed));
                return false;
            }
            try {
                if (tencent.isSessionValid()) {
                    tencent.logout(context);
                }
                String currScope = scope;
                if (scope == null || scope.isEmpty()) {
                    currScope = "all";
                }
                OnActionCallback callback = new OnActionCallback(1, listener);
                callback.isGetUserInfo = isGetUserInfo;
                instance.setMultiMedia(mMultiMedia)
                        .setActionCallback(callback);
                int status = tencent.login(activity, currScope, new QQEventHandler(tencent, new OnActionCallback(1, listener)));
                instance.e("QQ oauth launch status=" + status);
                return status > 0;
            } catch (Throwable t) {
                instance.e("QQ oauth launch fail.", t);
                instance.release();
                onFailure(instance, listener, -8004, t.getMessage());
                return false;
            }
        } else if (MultiMedia.ALIPAY == mMultiMedia) {
            if (authInfo != null && !authInfo.isEmpty()) {
                // 支付宝账户授权业务信息
                boolean postStatus = instance.postAsync(() -> {
                    Map<String, String> result;
                    try {
                        AuthTask alipay = new AuthTask(activity);
                        result = alipay.authV2(authInfo, true);
                    } catch (Throwable t) {
                        instance.e("Alipay oauth fail.", t);
                        onFailure(instance, listener, -8004, t.getMessage());
                        return;
                    }
                    AuthResult authResult = new AuthResult(result, true);
                    int status = authResult.getResultStatus();
                    int code = authResult.getResultCode();
                    if (status == 9000 && code == 200) {
                        // 授权成功
                        instance.i("Alipay oauth success. data=" + result);
                        Map<String, String> map = new HashMap<>();
                        map.put("memo", authResult.getMemo());
                        map.put("result", authResult.getResult());
                        map.put("authCode", authResult.getAuthCode());
                        map.put("alipay_open_id", authResult.getAlipayOpenId());
                        onComplete(instance, listener, map);
                    } else if (status == 6001) {
                        // 用户中途取消
                        instance.i("Alipay oauth cancel.");
                        onCancel(instance, listener);
                    } else {
                        instance.e("Alipay oauth fail. code=" + code);
                        onFailure(instance, listener, code, context.getString(R.string.multi_api_unknown_error));
                    }
                });
                if (!postStatus) {
                    onFailure(instance, listener, -8007, context.getString(R.string.multi_api_request_initiation_failed));
                    return false;
                }
                return true;
            }
            onFailure(instance, listener, -8003, context.getString(R.string.multi_api_parameter_error));
            return false;
        } else if (MultiMedia.UNION_PAY == mMultiMedia) {
            boolean isLegal;
            Platform platForm = instance.getPlatForm(mMultiMedia);
            String currScope = scope;
            if (scope == null || scope.isEmpty()) {
                currScope = "scope.base";
            } else {
                currScope = currScope.replace(",", "|");
            }
            OnActionCallback callback = new OnActionCallback(1, listener);
            instance.setMultiMedia(mMultiMedia)
                    .setActionCallback(callback);
            try {
                if (TextUtils.isEmpty(planId)) {
                    isLegal = UPAuthStart.LaunchUPActivity(activity, platForm.getAppId(), currScope);
                } else {
                    isLegal = UPAuthStart.nonSecertSigning(activity, platForm.getAppId(), currScope, planId);
                }
            } catch (Throwable t) {
                instance.e("UNION_PAY oauth launch fail.", t);
                instance.release();
                onFailure(instance, listener, -8004, t.getMessage());
                return false;
            }
            if (!isLegal) {
                // 表示传入参数是否合法, 若非法直接返回，不会启动云闪付 true:合法 false:非法
                instance.e("UNION_PAY oauth launch fail.");
                onFailure(instance, listener, -8003, context.getString(R.string.multi_api_parameter_error));
                return false;
            }
            return true;
        } else if (MultiMedia.WEIBO == mMultiMedia) {
            return instance.getWBApi(new Callback<IWBAPI>() {
                @Override
                public void onSuccess(@NonNull IWBAPI api) {
                    instance.i("WEIBO oauth start request.");
                    api.authorize(activity, new WbAuthListener() {
                        /**
                         * id	int64	用户UID
                         * idstr	string	字符串型的用户UID
                         * screen_name	string	用户昵称
                         * name	string	友好显示名称
                         * province	int	用户所在省级ID
                         * city	int	用户所在城市ID
                         * location	string	用户所在地
                         * description	string	用户个人描述
                         * url	string	用户博客地址
                         * profile_image_url	string	用户头像地址（中图），50×50像素
                         * profile_url	string	用户的微博统一URL地址
                         * domain	string	用户的个性化域名
                         * weihao	string	用户的微号
                         * gender	string	性别，m：男、f：女、n：未知
                         * followers_count	int	粉丝数
                         * friends_count	int	关注数
                         * statuses_count	int	微博数
                         * favourites_count	int	收藏数
                         * created_at	string	用户创建（注册）时间
                         * following	boolean	暂未支持
                         * allow_all_act_msg	boolean	是否允许所有人给我发私信，true：是，false：否
                         * geo_enabled	boolean	是否允许标识用户的地理位置，true：是，false：否
                         * verified	boolean	是否是微博认证用户，即加V用户，true：是，false：否
                         * verified_type	int	暂未支持
                         * remark	string	用户备注信息，只有在查询用户关系时才返回此字段
                         * status	object	用户的最近一条微博信息字段 详细
                         * allow_all_comment	boolean	是否允许所有人对我的微博进行评论，true：是，false：否
                         * avatar_large	string	用户头像地址（大图），180×180像素
                         * avatar_hd	string	用户头像地址（高清），高清头像原图
                         * verified_reason	string	认证原因
                         * follow_me	boolean	该用户是否关注当前登录用户，true：是，false：否
                         * online_status	int	用户的在线状态，0：不在线、1：在线
                         * bi_followers_count	int	用户的互粉数
                         * lang	string	用户当前的语言版本，zh-cn：简体中文，zh-tw：繁体中文，en：英语
                         *
                         * @param token
                         */
                        @Override
                        public void onComplete(Oauth2AccessToken token) {
                            if (token.isSessionValid()) {
                                instance.i("WEIBO oauth success response. data=" + token);
                                String uid = token.getUid();
                                String refreshToken = token.getRefreshToken();
                                long expiration = token.getExpiresTime();
                                String accessToken = token.getAccessToken();
                                if (!isGetUserInfo) {
                                    Map<String, String> map = new HashMap<>();
                                    map.put("accessToken", accessToken);
                                    map.put("refreshToken", refreshToken);
                                    map.put("expiration", expiration + "");
                                    map.put("openid", token.getUid());
                                    OauthAction.this.onComplete(instance, listener, map);
                                    return;
                                }
                                String url = "https://api.weibo.com/2/users/show.json?access_token=" + accessToken + "&uid=" + uid;
                                instance.i("WEIBO getUserInfo start request.");
                                boolean status = instance.request(url, new Callback<JSONObject>() {
                                    @Override
                                    public void onSuccess(@NonNull JSONObject jsonObject) {
                                        instance.i("WEIBO getUserInfo success response. data=" + jsonObject);
                                        Map<String, String> map = new HashMap<>();
                                        try {
                                            map.put("accessToken", accessToken);
                                            map.put("refreshToken", refreshToken);
                                            map.put("expiration", expiration + "");
                                            map.put("openid", jsonObject.getString("uid"));
                                            map.put("nickname", jsonObject.getString("screen_name"));
                                            map.put("iconUrl", jsonObject.getString("profile_image_url"));
                                            String gender = jsonObject.getString("gender");
                                            int sex = 0;
                                            if ("m".equals(gender)) {
                                                // 男
                                                sex = 1;
                                            } else if ("f".equals(gender)) {
                                                // 女
                                                sex = 2;
                                            }
                                            map.put("sex", sex + "");
                                            map.put("location", jsonObject.getString("location"));
                                            map.put("followers_count", jsonObject.getInt("followers_count") + "");
                                            map.put("friends_count", jsonObject.getInt("friends_count") + "");
                                        } catch (Throwable t) {
                                            t.printStackTrace();
                                        }
                                        OauthAction.this.onComplete(instance, listener, map);
                                    }

                                    @Override
                                    public void onFailure(int code, @NonNull String msg) {
                                        instance.e("WEIBO getUserInfo fail response. code=" + code + ", message=" + msg);
                                        OauthAction.this.onFailure(instance, listener, code, msg);
                                    }
                                });
                                if (!status) {
                                    OauthAction.this.onFailure(instance, listener, -8007, context.getString(R.string.multi_api_request_initiation_failed));
                                }
                            } else {
                                instance.e("WEIBO oauth fail response. accessToken invalid.");
                                OauthAction.this.onFailure(instance, listener, -9002, context.getString(R.string.multi_api_access_token_acquisition_failed));
                            }
                        }

                        @Override
                        public void onError(UiError uiError) {
                            int errorCode = -9000;
                            String errorMsg = "";
                            if (uiError != null) {
                                errorCode = uiError.errorCode;
                                errorMsg = uiError.errorMessage;
                            }
                            if (TextUtils.isEmpty(errorMsg)) {
                                errorMsg = context.getString(R.string.multi_api_privilege_grant_failed);
                            }
                            instance.e("WEIBO oauth fail response. code=" + errorCode + ", message=" + errorMsg);
                            OauthAction.this.onFailure(instance, listener, errorCode, errorMsg);
                        }

                        @Override
                        public void onCancel() {
                            instance.i("WEIBO oauth cancel response.");
                            OauthAction.this.onCancel(instance, listener);
                        }
                    });
                }

                @Override
                public void onFailure(int code, @NonNull String msg) {
                    OauthAction.this.onFailure(instance, listener, code, msg);
                }
            });
        } else if (MultiMedia.GOOGLE == mMultiMedia) {
            // Google
            CredentialManager credentialManager = instance.getCredentialManager();
            if (credentialManager == null) {
                onFailure(instance, listener, -8005, context.getString(R.string.multi_api_not_initialized_successfully));
                return false;
            }
            Executor executor = instance.getExecutor();
            ClearCredentialStateRequest clearCredentialStateRequest = new ClearCredentialStateRequest();
            instance.i("Google clearCredentialState start request.");
            credentialManager.clearCredentialStateAsync(clearCredentialStateRequest, new CancellationSignal(), executor, new CredentialManagerCallback<Void, ClearCredentialException>() {
                @Override
                public void onResult(Void unused) {
                    instance.i("Google clearCredentialState success response.");
                    startGoogleLogin(instance, listener, credentialManager, activity, executor);
                }

                @Override
                public void onError(@NonNull ClearCredentialException e) {
                    instance.e("Google clearCredentialState fail response.", e);
                    startGoogleLogin(instance, listener, credentialManager, activity, executor);
                }
            });
        } else if (MultiMedia.FACEBOOK == mMultiMedia) {
            // Facebook
            CallbackManager callbackManager = instance.getCallbackManager();
            if (callbackManager == null) {
                onFailure(instance, listener, -8005, context.getString(R.string.multi_api_not_initialized_successfully));
                return false;
            }
            if (!instance.isInstalled(mMultiMedia)) {
                // 未安装Facebook
                onFailure(instance, listener, -8001, context.getString(R.string.multi_api_app_not_installed));
                return false;
            }
            if (AccessToken.isCurrentAccessTokenActive()) {
                LoginManager.getInstance().logOut();
            }
            instance.i("Facebook oauth start request.");
            LoginManager.getInstance().registerCallback(callbackManager,
                    new FacebookCallback<LoginResult>() {
                        @Override
                        public void onSuccess(LoginResult loginResult) {
                            AccessToken accessToken = loginResult.getAccessToken();
                            Set<String> deniedPermissions = loginResult.getRecentlyDeniedPermissions();
                            String deniedStr = "";
                            for (String permission : deniedPermissions) {
                                if (!deniedStr.isEmpty()) {
                                    deniedStr += ",";
                                }
                                deniedStr += permission;
                            }
                            instance.e("Facebook oauth success response. deniedPermission=" + deniedStr);
                            if (isGetUserInfo) {
                                Set<String> permissions = loginResult.getRecentlyGrantedPermissions();
                                String fields = "";
                                for (String permission : permissions) {
                                    if ("public_profile".equals(permission)) {
                                        if (!fields.isEmpty()) {
                                            fields += ",";
                                        }
                                        fields += "id,name,gender,picture.type(normal)";
                                    } else if ("email".equals(permission)) {
                                        if (!fields.isEmpty()) {
                                            fields += ",";
                                        }
                                        fields += "email";
                                    }
                                }
                                getFacebookUserProfile(instance, listener, accessToken, fields, deniedStr);
                            } else {
                                Map<String, String> map = new HashMap<>();
                                map.put("accessToken", accessToken.getToken());
                                map.put("expiration", accessToken.getExpires().getTime() + "");
                                map.put("openid", accessToken.getUserId());
                                map.put("deniedPermissions", deniedStr);
                                onComplete(instance, listener, map);
                            }
                        }

                        @Override
                        public void onCancel() {
                            instance.e("Facebook oauth cancel response.");
                            OauthAction.this.onCancel(instance, listener);
                        }

                        @Override
                        public void onError(@NonNull FacebookException exception) {
                            instance.e("Facebook oauth fail response.", exception);
                            onFailure(instance, listener, -9000, exception.getMessage());
                        }
                    });
            List<String> list = new ArrayList<>();
            if (scope == null || scope.isEmpty()) {
                list.add("public_profile");
            } else {
                String[] strings = scope.split(",");
                list = Arrays.asList(strings);
            }
            OnActionCallback callback = new OnActionCallback(1, listener);
            instance.setMultiMedia(mMultiMedia)
                    .setActionCallback(callback);
            try {
                LoginManager.getInstance().logInWithReadPermissions(activity, list);
            } catch (Exception e) {
                instance.release();
                onFailure(instance, listener, -8004, e.getMessage());
            }
        } else {
            onFailure(instance, listener, -8002, context.getString(R.string.multi_api_feature_not_supported));
        }
        return false;
    }

    /**
     * 启动Google登录
     *
     * @param instance
     * @param listener
     * @param credentialManager
     * @param activity
     * @param executor
     */
    private void startGoogleLogin(@NonNull MultiApi instance, OnActionListener listener, CredentialManager credentialManager, Activity activity, Executor executor) {
        Platform platForm = instance.getPlatForm(mMultiMedia);
        Context context = instance.getContext();
        GetGoogleIdOption googleIdOption = new GetGoogleIdOption.Builder()
                .setFilterByAuthorizedAccounts(true)
                .setServerClientId(platForm.getAppId())
//                    .setAutoSelectEnabled(true)
                .setNonce("")
                .build();

        GetCredentialRequest request = new GetCredentialRequest.Builder()
                .addCredentialOption(googleIdOption)
                .build();
        CancellationSignal cancellationSignal = new CancellationSignal();
        instance.i("Google getUserInfo start request.");
        credentialManager.getCredentialAsync(activity, request, cancellationSignal, executor, new CredentialManagerCallback<GetCredentialResponse, GetCredentialException>() {
            @Override
            public void onResult(GetCredentialResponse result) {
                Credential credential = result.getCredential();
                if (credential instanceof CustomCredential) {
                    if (GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL.equals(credential.getType())) {
                        GoogleIdTokenCredential googleIdTokenCredential = GoogleIdTokenCredential
                                .createFrom(credential.getData());
                        instance.i("Google getUserInfo success response. data=" + googleIdTokenCredential);
                        Map<String, String> map = new HashMap<>();
                        map.put("accessToken", googleIdTokenCredential.getIdToken());
                        map.put("openid", googleIdTokenCredential.getId());
                        map.put("nickname", googleIdTokenCredential.getDisplayName());
                        Uri pictureUri = googleIdTokenCredential.getProfilePictureUri();
                        if (pictureUri != null) {
                            map.put("iconUrl", pictureUri.toString());
                        }
                        onComplete(instance, listener, map);
                    } else {
                        // 授权失败
                        instance.e("Google getUserInfo fail response.");
                        onFailure(instance, listener, -9001, context.getString(R.string.multi_api_access_token_acquisition_failed));
                    }
                } else {
                    // 授权失败
                    instance.e("Google getUserInfo fail response. credential is not CustomCredential.");
                    onFailure(instance, listener, -9001, context.getString(R.string.multi_api_access_token_acquisition_failed));
                }
            }

            @Override
            public void onError(@NonNull GetCredentialException e) {
                instance.e("Google getUserInfo fail response.", e);
                if (e instanceof GetCredentialCancellationException) {
                    // 用户取消
                    onCancel(instance, listener);
                } else {
                    onFailure(instance, listener, -9000, e.getMessage());
                }
            }
        });
    }

    /**
     * 获取Facebook用户信息
     *
     * @param accessToken
     */
    private void getFacebookUserProfile(@NonNull MultiApi instance, OnActionListener listener, AccessToken accessToken, String fields, String deniedPermissions) {
        instance.i("Facebook getUserInfo start request.");
        GraphRequest request = GraphRequest.newMeRequest(
                accessToken,
                (object, response) -> {
                    instance.i("Facebook getUserInfo success response. data=" + object);
                    try {
                        if (object != null) {
                            Map<String, String> map = new HashMap<>();

                            map.put("accessToken", accessToken.getToken());
                            map.put("expiration", accessToken.getExpires().getTime() + "");
                            map.put("deniedPermissions", deniedPermissions);
                            if (object.has("id")) {
                                map.put("openid", object.getString("id"));
                            }
                            if (object.has("name")) {
                                map.put("nickname", object.getString("name"));
                            }
                            if (object.has("gender")) {
                                String gender = object.getString("gender");
                                int sex = 0;
                                if ("male".equals(gender)) {
                                    sex = 1;
                                } else if ("female".equals(gender)) {
                                    sex = 2;
                                }
                                map.put("gender", sex + "");
                            }
                            if (object.has("picture")) {
                                try {
                                    JSONObject picture = object.getJSONObject("picture");
                                    JSONObject data = picture.getJSONObject("data");
                                    String imageUrl = data.getString("url");
                                    map.put("iconUrl", imageUrl);
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            }
                            if (object.has("email")) {
                                map.put("email", object.getString("email"));
                            }
                            onComplete(instance, listener, map);
                        } else if (response != null) {
                            FacebookRequestError error = response.getError();
                            int errorCode = -9000;
                            String errorMsg = "";
                            if (error != null) {
                                errorCode = error.getErrorCode();
                                errorMsg = error.getErrorMessage();
                            }
                            if (TextUtils.isEmpty(errorMsg)) {
                                errorMsg = instance.getContext().getString(R.string.multi_api_privilege_grant_failed);
                            }
                            instance.e("Facebook getUserInfo fail response. code=" + errorCode + ", message=" + errorMsg);
                            onFailure(instance, listener, errorCode, errorMsg);
                        } else {
                            instance.e("Facebook getUserInfo fail response.");
                            onFailure(instance, listener, -9000, instance.getContext().getString(R.string.multi_api_privilege_grant_failed));
                        }
                    } catch (Exception e) {
                        onFailure(instance, listener, -9900, e.getMessage());
                    }
                });

        Bundle parameters = new Bundle();
        parameters.putString("fields", fields);
        request.setParameters(parameters);
        request.executeAsync();
    }

    /**
     * 完成回调监听
     *
     * @param listener
     * @param map
     */
    private void onComplete(@NonNull MultiApi instance, OnActionListener listener, @NonNull Map<String, String> map) {
        if (listener == null) {
            return;
        }
        MultiMedia multiMedia = mMultiMedia;
        instance.post(() -> listener.onComplete(multiMedia, map));
    }

    /**
     * 取消回调监听
     *
     * @param listener
     */
    private void onCancel(@NonNull MultiApi instance, OnActionListener listener) {
        if (listener == null) {
            return;
        }
        MultiMedia multiMedia = mMultiMedia;
        instance.post(() -> listener.onCancel(multiMedia));
    }

    /**
     * 失败回调监听
     *
     * @param listener
     * @param code
     */
    private void onFailure(@NonNull MultiApi instance, OnActionListener listener, int code, String msg) {
        if (listener == null) {
            return;
        }
        MultiMedia multiMedia = mMultiMedia;
        instance.post(() -> listener.onFailure(multiMedia, code, msg));
    }
}
